package miggy.ui;

import miggy.DisassembledItem;
import miggy.SystemModel;
import miggy.cpu.InstructionDecoder;
import miggy.utils.TextUtil;

import javax.swing.table.AbstractTableModel;
import java.util.logging.Level;
import java.util.logging.Logger;

/*
//  Miggy - Java Amiga MachineCore
//  Copyright (c) 2008, Tony Headford
//  All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
//  following conditions are met:
//
//    o  Redistributions of source code must retain the above copyright notice, this list of conditions and the
//       following disclaimer.
//    o  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
//       following disclaimer in the documentation and/or other materials provided with the distribution.
//    o  Neither the name of the Miggy Project nor the names of its contributors may be used to endorse or promote
//       products derived from this software without specific prior written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
//  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
//  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
//  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
//  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
//  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
//  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// $Revision: 21 $
*/
public final class RegisterModel extends AbstractTableModel
{
	private static Logger logger = Logger.getLogger(RegisterModel.class.getName());
	private static final String[] col0 = { "D0 = ", "D1 = ", "D2 = ", "D3 = ", "D4 = ", "D5 = ", "D6 = ", "D7 = ", "SR = ", "US = " };
	private static final String[] col3 = { "A0 = ", "A1 = ", "A2 = ", "A3 = ", "A4 = ", "A5 = ", "A6 = ", "A7 = ", "PC = ", "SS = " };

	public final void updateAll()
	{
		//call this after running the emulator or stepping even
		fireTableStructureChanged();
	}

	@Override
	public final boolean isCellEditable(int row, int col)
	{
		return (col == 1 || col == 4);
	}

	/**
	 * Returns the number of rows in the model. A
	 * <code>JTable</code> uses this method to determine how many rows it
	 * should display.  This method should be quick, as it
	 * is called frequently during rendering.
	 *
	 * @return the number of rows in the model
	 * @see #getColumnCount
	 */
	public final int getRowCount()
	{
		return 10;
	}

	/**
	 * Returns the number of columns in the model. A
	 * <code>JTable</code> uses this method to determine how many columns it
	 * should create and display by default.
	 *
	 * @return the number of columns in the model
	 * @see #getRowCount
	 */
	public final int getColumnCount()
	{
		return 6;
	}

	/**
	 * Returns the value for the cell at <code>columnIndex</code> and
	 * <code>rowIndex</code>.
	 *
	 * @param	rowIndex	the row whose value is to be queried
	 * @param	columnIndex the column whose value is to be queried
	 * @return the value Object at the specified cell
	 */
	public final Object getValueAt(int rowIndex, int columnIndex)
	{
		if(rowIndex >= 0)	// -1 for heading
		{
			switch(columnIndex)
			{
				case 0:
				{
					return col0[rowIndex];
				}
				case 1:
				{
					if(rowIndex < 8)
						return TextUtil.toHex(SystemModel.CPU.getDataRegister(rowIndex));
					else if(rowIndex == 8)
						return TextUtil.toHex(SystemModel.CPU.getSR());
					else
						return TextUtil.toHex(SystemModel.CPU.getUSP());
				}
				case 2:
				{
					if(rowIndex < 8)
					{
						return TextUtil.toAscii(SystemModel.CPU.getDataRegister(rowIndex));
					}
					else if(rowIndex == 8)
					{
						//SR flags
						return TextUtil.getSRFlags();
					}
					break;
				}
				case 3:
				{
					return col3[rowIndex];
				}
				case 4:
				{
					if(rowIndex < 8)
						return TextUtil.toHex(SystemModel.CPU.getAddrRegister(rowIndex));
					else if(rowIndex == 8)
						return TextUtil.toHex(SystemModel.CPU.getPC());
					else
						return TextUtil.toHex(SystemModel.CPU.getSSP());
				}
				case 5:
				{
					if(rowIndex < 8)
					{
						//"00 00 00 00 00 00 00 00  ........";
						return TextUtil.makeMemView(SystemModel.CPU.getAddrRegister(rowIndex));
					}
					else if(rowIndex == 8)
					{
						DisassembledItem item = DisassembledItem.makeDisassembledItem(InstructionDecoder.decode(SystemModel.CPU.getPC()));
						return item.getInstruction();
					}
				}
			}
		}
		return null;
	}

	@Override
	public final void setValueAt(Object value, int rowIndex, int columnIndex)
	{
		int i;

		try
		{
			i = (int)Long.parseLong((String)value, 16);
		}
		catch(NumberFormatException e)
		{
			logger.log(Level.WARNING,  "Invalid hex number " + value, e);
			return;
		}

		if(columnIndex == 1)
		{
			//data and status regs
			if(rowIndex < 8)
			{
				//data reg
				SystemModel.CPU.setDataRegister(rowIndex, i);
			}
			else if(rowIndex == 8)
			{
				//sr
				SystemModel.CPU.setSR((short)i);
			}
			else
			{
				//usp
				SystemModel.CPU.setUSP(i);
			}
		}
		else if(columnIndex == 4)
		{
			//addr and PC regs
			if(rowIndex < 8)
			{
				//data reg
				SystemModel.CPU.setAddrRegister(rowIndex, i);
			}
			else if(rowIndex == 8)
			{
				//PC
				SystemModel.CPU.setPC(i);
			}
			else
			{
				//SSP
				SystemModel.CPU.setSSP(i);
			}
		}

		//force update of the next cell
		fireTableCellUpdated(rowIndex, columnIndex + 1);
	}
}
